package com.cpe.transfer.student;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.javatuples.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import com.cpe.data.domain.physique.score.PhysiqueScore;
import com.cpe.data.domain.physique.score.PhysiqueScoreQuery;
import com.cpe.data.domain.student.Student;
import com.cpe.data.domain.student.physique.StudentHistoryPhysique;
import com.cpe.data.domain.student.physique.StudentPhysique;
import com.cpe.data.domain.student.physique.StudentPhysiqueForm;
import com.cpe.data.domain.student.physique.StudentPhysiqueInfo;
import com.cpe.repository.mapper.physique.PhysiqueScoreMapper;
import com.cpe.repository.mapper.student.StudentMapper;
import com.cpe.repository.mapper.student.StudentPhysiqueMapper;
import com.cpe.transfer.physique.PhysiqueScoreTransfer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.util.math.CalcUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class StudentPhysiqueTransfer {

	@Resource
	private StudentMapper studentMapper;

	@Resource
	private PhysiqueScoreMapper physiqueScoreMapper;

	@Resource
	private StudentPhysiqueMapper studentPhysiqueMapper;

	@Resource
	private PhysiqueScoreTransfer physiqueScoreTransfer;

	/**
	 * 表单-->实体
	 */
	public StudentPhysique toEntity(StudentPhysiqueForm form) throws ParseException {
		Assert.notNull(form);
		StudentPhysique studentPhysique = new StudentPhysique();
		BeanUtils.copyProperties(form, studentPhysique);
		studentPhysique.setScoreDate(new SimpleDateFormat("yyyy-MM-dd").parse(form.getScoreDate()));
		studentPhysique.setCreateTime(new Date());
		Integer value = calcValue(form.getPhysiqueName(), form.getScore(), form.getStudentId());
		studentPhysique.setValue(value);
		log.debug(studentPhysique.toString());
		return studentPhysique;
	}

	/**
	 * 表单-->实体
	 */
	public Pair<StudentPhysique, StudentPhysique> toEntities(StudentPhysiqueForm form) throws ParseException {
		final StudentPhysique studentPhysique = toEntity(form);
		final StudentPhysique studentShape = generateStudentSahpe(studentPhysique);
		return Pair.with(studentPhysique, studentShape);
	}

	/**
	 * 生成一条体型记录
	 * 
	 * @param studentPhysique
	 *            当前录入的体质成绩记录
	 */
	public StudentPhysique generateStudentSahpe(StudentPhysique studentPhysique) {
		// 体型项目
		StudentPhysique studentShape = null;
		String physiqueName = "体型";
		if ("身高".equals(studentPhysique.getPhysiqueName())) {
			// 如果当天该学生录入了体重成绩，则再插入一条体型成绩
			StudentPhysique query = new StudentPhysique();
			BeanUtils.copyProperties(studentPhysique, query);
			query.setPhysiqueName("体重");
			StudentPhysique studentWeight = studentPhysiqueMapper.findOne(query);
			if (studentWeight != null) {
				studentShape = new StudentPhysique();
				studentShape.setPhysiqueName(physiqueName);
				studentShape.setScoreDate(studentPhysique.getScoreDate());
				studentShape.setCreateTime(studentPhysique.getCreateTime());
				studentShape.setStudentId(studentPhysique.getStudentId());
				// 计算分值
				Float height = studentPhysique.getScore();
				Float weight = studentWeight.getScore();
				Pair<Integer, Integer> pair = calcShapeValue(height, weight, studentPhysique.getStudentId());
				studentShape.setValue(pair.getValue0());
				studentShape.setLowOrHigh(pair.getValue1());
				studentShape.setScore(weight / (height * height / 10000));
			}
		} else if ("体重".equals(studentPhysique.getPhysiqueName())) {
			// 如果当天该学生录入了身高成绩，则再插入一条体型成绩
			StudentPhysique query = new StudentPhysique();
			BeanUtils.copyProperties(studentPhysique, query);
			query.setPhysiqueName("身高");
			StudentPhysique studentHeight = studentPhysiqueMapper.findOne(query);
			if (studentHeight != null) {
				studentShape = new StudentPhysique();
				studentShape.setPhysiqueName(physiqueName);
				studentShape.setScoreDate(studentPhysique.getScoreDate());
				studentShape.setCreateTime(studentPhysique.getCreateTime());
				studentShape.setStudentId(studentPhysique.getStudentId());
				// 计算分值
				Float height = studentHeight.getScore();
				Float weight = studentPhysique.getScore();
				Pair<Integer, Integer> pair = calcShapeValue(height, weight, studentPhysique.getStudentId());
				studentShape.setValue(pair.getValue0());
				studentShape.setLowOrHigh(pair.getValue1());
				studentShape.setScore(weight / (height * height / 10000));
			}
		}
		return studentShape;
	}

	/**
	 * 查询分值
	 * 
	 * @return
	 */
	public Integer calcValue(String physiqueName, Float score, String studentId) {
		Student student = studentMapper.findById(studentId);
		Integer sex = student.getSex();
		Float age = CalcUtil.getRealAge(student.getBirthday());
		PhysiqueScoreQuery query = new PhysiqueScoreQuery();
		query.setAge(age);
		query.setPhysiqueName(physiqueName);
		query.setScore(score);
		query.setSex(sex);
		PhysiqueScore physiqueScore = physiqueScoreMapper.findOneByCustomQuery(query);
		if (physiqueScore != null) {
			return physiqueScore.getValue();
		} else {
			return 5;
		}
	}

	/**
	 * 查询体型项目的分值，并计算出偏高还是偏低
	 * 
	 * @return
	 */
	public Pair<Integer, Integer> calcShapeValue(Float heightScore, Float wigthScore, String studentId) {
		Assert.hasText(studentId);
		Student student = studentMapper.findById(studentId);
		Integer sex = student.getSex();
		Float age = CalcUtil.getRealAge(student.getBirthday());
		return physiqueScoreTransfer.calcShapeValue(heightScore, wigthScore, sex, age);
	}

	/**
	 * 实体集->特殊结构响应：按照体质名称重构
	 */
	public List<StudentHistoryPhysique> toHistoryPhysique(List<StudentPhysiqueInfo> studentPhysiqueInfos) {
		List<StudentHistoryPhysique> result = Lists.newArrayList();
		Map<String, List<StudentPhysiqueInfo>> map = Maps.newHashMap();
		Calendar calendar = Calendar.getInstance();

		// 按照体质项目进行分组
		for (StudentPhysiqueInfo info : studentPhysiqueInfos) {
			if (map.containsKey(info.getPhysiqueName())) {
				map.get(info.getPhysiqueName()).add(info);
			} else {
				map.put(info.getPhysiqueName(), Lists.newArrayList(info));
			}
		}

		PhysiqueScoreQuery query = new PhysiqueScoreQuery();
		for (Entry<String, List<StudentPhysiqueInfo>> entry : map.entrySet()) {
			// 计算单个体质项目的历史成绩
			StudentHistoryPhysique studentHistoryPhysique = new StudentHistoryPhysique();
			List<StudentPhysiqueInfo> oneGroup = entry.getValue();
			// 计算各个月份及对应的成绩（x轴为月份，y轴为成绩）
			List<String> monthCategory = Lists.newArrayList();
			List<Float> scores = Lists.newArrayList();
			List<Float> standardUpScores = Lists.newArrayList();
			List<Float> standardDownScores = Lists.newArrayList();
			oneGroup.forEach(info -> {
				calendar.setTime(info.getScoreDate());
				int month = calendar.get(Calendar.MONTH) + 1;
				monthCategory.add(month + "月");
				scores.add(info.getScore());
				// 查询标准分值
				query.setPhysiqueName(entry.getKey());
				query.setAge(CalcUtil.getRealAge(info.getBirthday(), info.getScoreDate()));
				query.setSex(info.getSex());
				query.setValue(5);
				PhysiqueScore physiqueScore = physiqueScoreMapper.findOneByCustomQuery(query);
				if (physiqueScore == null) {
					standardUpScores.add(0f);
					standardDownScores.add(0f);
				} else {
					standardUpScores.add(physiqueScore.getMaxValue());
					standardDownScores.add(physiqueScore.getMinValue());
				}
			});
			studentHistoryPhysique.setPhysiqueName(entry.getKey());
			studentHistoryPhysique.setUnit(oneGroup.get(0).getUnit());
			studentHistoryPhysique.setMonthCategory(monthCategory);
			studentHistoryPhysique.setScores(scores);
			studentHistoryPhysique.setStandardUpScores(standardUpScores);
			studentHistoryPhysique.setStandardDownScores(standardDownScores);
			result.add(studentHistoryPhysique);
		}
		return result;
	}
}
